package fr.sharpe.app.earthvisualizationproject.controller;


import fr.sharpe.app.earthvisualizationdatamodel.Icon;
import fr.sharpe.app.earthvisualizationdatamodel.Line;
import fr.sharpe.app.earthvisualizationdatamodel.MarkerPoint;
import fr.sharpe.app.earthvisualizationdatamodel.Surface;
import fr.sharpe.app.earthvisualizationdatamodel.Text;
import fr.sharpe.app.earthvisualizationproject.event.AddIconsEvent;
import fr.sharpe.app.earthvisualizationproject.event.AddMarkerPointsEvent;
import fr.sharpe.app.earthvisualizationproject.event.AddSurfacesEvent;
import fr.sharpe.app.earthvisualizationproject.event.AddTextsEvent;
import fr.sharpe.app.earthvisualizationproject.event.DeleteLayerEvent;
import fr.sharpe.app.earthvisualizationproject.model.EarthLayer;
import fr.sharpe.app.earthvisualizationproject.model.SelectedObjectData;
import fr.sharpe.app.earthvisualizationproject.ui.DataDisplayLayer;
import fr.sharpe.app.earthvisualizationproject.ui.Earth;
import fr.sharpe.app.earthvisualizationproject.ui.EarthView;
import fr.sharpe.app.earthvisualizationproject.ui.ImageView;
import fr.sharpe.app.earthvisualizationproject.ui.Layers;
import fr.sharpe.app.earthvisualizationproject.ui.Stats;
import gov.nasa.worldwind.event.SelectEvent;
import gov.nasa.worldwind.event.SelectListener;
import gov.nasa.worldwind.layers.AnnotationLayer;
import gov.nasa.worldwind.layers.IconLayer;
import gov.nasa.worldwind.layers.MarkerLayer;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.AbstractSurfaceObject;
import gov.nasa.worldwind.render.Annotation;
import gov.nasa.worldwind.render.GlobeAnnotation;
import gov.nasa.worldwind.render.Polyline;
import gov.nasa.worldwind.render.Renderable;
import gov.nasa.worldwind.render.UserFacingIcon;
import gov.nasa.worldwind.render.WWIcon;
import gov.nasa.worldwind.render.markers.BasicMarker;
import gov.nasa.worldwind.render.markers.Marker;

import java.awt.event.ActionEvent;
import java.util.ArrayList;

import com.mycila.event.api.Dispatcher;
import com.mycila.event.api.Event;
import com.mycila.event.api.annotation.Subscribe;

public class EarthController implements SelectListener{
	
	private Earth earth;
	private EarthView earthView;
	private Stats stats;
	private Layers layers;
	private ImageView imageView;
	private Dispatcher dispatcher;
	private CacheLayerController cacheOfLayers;
	private DataDisplayLayer dataLayer; 
	private SelectedObjectData selectedObjectData;
	
	public EarthController(Dispatcher dispatcherIn)
	{
		this.dispatcher = dispatcherIn;
		cacheOfLayers = CacheLayerController.getInstance();
		selectedObjectData = SelectedObjectData.getInstance();

		earth = Earth.getInstance();
		earth.getWwd().addSelectListener(this);
		
		imageView = new ImageView();

        java.awt.EventQueue.invokeLater(new Runnable()
        {
        	public void run()
            {
                // Create an AppFrame and immediately make it visible. As per Swing convention, this
                // is done within an invokeLater call so that it executes on an AWT thread.
                earthView = new EarthView();
                earthView.setVisible(true);

                stats = new Stats();
                stats.setVisible(true);

                layers = new Layers();
                layers.setVisible(true);
                
                dataLayer = (DataDisplayLayer) earth.getLayer("DataDisplayLayer");
                
            }
        });

	}	
	
	@Subscribe(topics = "AddMarkerPoints", eventType = AddMarkerPointsEvent.class)
	public void onAddMarkers(Event<AddMarkerPointsEvent> event)
	{
		final String layerName = event.getSource().getLayerName();
	
		if(!this.cacheOfLayers.containsKey(layerName))
		{
			System.out.println("Adding layer "+ layerName);
			this.cacheOfLayers.addLayer(layerName, BasicMarker.class);
			MarkerLayer markerLayer = new MarkerLayer();
			markerLayer.setName(layerName);
			earth.addLayer(markerLayer);
			layers.updatePanel();
		}
		
		final MarkerLayer layer = (MarkerLayer) earth.getLayer(layerName);
		if(layer != null)//TODO Maybe impossible 
    	{
			for(MarkerPoint m:event.getSource().getMarkers())
			{
				this.cacheOfLayers.getLayer(layerName).update(m.getId(), m, m.getPoint());
				
			}
			if(earth.getLayer("DataDisplayLayer").isEnabled() && this.selectedObjectData.getMarker() != null)
			{
				this.selectedObjectData.updateSelectedObject(this.cacheOfLayers.getLayer(layerName).getOriginalObjects(), MarkerPoint.class);
			}
			final ArrayList<Marker> cacheTmp = new ArrayList<Marker>();
			for(String key: this.cacheOfLayers.getLayer(layerName).getConvertedObjects().keySet())
			{
				cacheTmp.add((Marker) this.cacheOfLayers.getLayer(layerName).getConvertedObjects().get(key));
			}
			java.awt.EventQueue.invokeLater(new Runnable()
	        {
	            public void run()
	            {
	            	layer.setMarkers(cacheTmp);
	            	earthView.update();

	            }
	        });
    	}
		else
    	{
    		System.out.println("Fail Layer "+layerName+" don't exist");
    	}
	}
	
	@Subscribe(topics = "AddSurfaces", eventType = AddSurfacesEvent.class)
	public void onAddSurfaces(Event<AddSurfacesEvent> event)
	{

		final String layerName = event.getSource().getLayerName();
		final ArrayList<AbstractSurfaceObject> surfaces = new ArrayList<AbstractSurfaceObject>();
		
		
		if(!this.cacheOfLayers.containsKey(layerName))
		{
			this.cacheOfLayers.addLayer(layerName, Polyline.class);
			RenderableLayer renderableLayer = new RenderableLayer();
			renderableLayer.setName(layerName);
			earth.addLayer(renderableLayer);
			layers.updatePanel();
		}
		
		final RenderableLayer layer = (RenderableLayer) earth.getLayer(layerName);
    	if(layer != null)
    	{
			for(Surface s:event.getSource().getShapes())
			{
				this.cacheOfLayers.getLayer(layerName).update(s.getId(),s,s.getShape());	
			}
			if(earth.getLayer("DataDisplayLayer").isEnabled() && this.selectedObjectData.getLine() != null)
			{
				this.selectedObjectData.updateSelectedObject(this.cacheOfLayers.getLayer(layerName).getOriginalObjects(), Line.class);
			}
			final ArrayList<Renderable> cacheTmp = new ArrayList<Renderable>();
			for(String key: this.cacheOfLayers.getLayer(layerName).getConvertedObjects().keySet())
			{
				cacheTmp.add((Renderable) this.cacheOfLayers.getLayer(layerName).getConvertedObjects().get(key));
			}
			
			java.awt.EventQueue.invokeLater(new Runnable()
	        {

	            public void run()
	            {
	            	layer.setRenderables(cacheTmp);
	            	earthView.update();
	            	
	            }
	        });
    	}
    	else
    	{
    		System.out.println("Fail Layer "+layerName+" don't exist");
    	}
	}
	
	@Subscribe(topics = "AddIcons", eventType = AddIconsEvent.class)
	public void onAddIcons(Event<AddIconsEvent> event)
	{

		final String layerName = event.getSource().getLayerName();
		final ArrayList<AbstractSurfaceObject> surfaces = new ArrayList<AbstractSurfaceObject>();
		
		
		if(!this.cacheOfLayers.containsKey(layerName))
		{
			this.cacheOfLayers.addLayer(layerName, UserFacingIcon.class);
			IconLayer iconLayer = new IconLayer();
			iconLayer.setName(layerName);
			earth.addLayer(iconLayer);
			layers.updatePanel();
		}
		
		final IconLayer layer = (IconLayer) earth.getLayer(layerName);
    	if(layer != null)
    	{
			for(Surface s:event.getSource().getShapes())
			{
				this.cacheOfLayers.getLayer(layerName).update(s.getId(),s,s.getShape());	
			}
			if(earth.getLayer("DataDisplayLayer").isEnabled() && this.selectedObjectData.getIcon() != null)
			{
				this.selectedObjectData.updateSelectedObject(this.cacheOfLayers.getLayer(layerName).getOriginalObjects(), Icon.class);
			}
			final ArrayList<WWIcon> cacheTmp = new ArrayList<WWIcon>();
			for(String key: this.cacheOfLayers.getLayer(layerName).getConvertedObjects().keySet())
			{
				cacheTmp.add((WWIcon) this.cacheOfLayers.getLayer(layerName).getConvertedObjects().get(key));
			}
			
			java.awt.EventQueue.invokeLater(new Runnable()
	        {

	            public void run()
	            {
	            	layer.setIcons(cacheTmp);
	            	earthView.update();
	            	
	            }
	        });
    	}
    	else
    	{
    		System.out.println("Fail Layer "+layerName+" don't exist");
    	}
	}
	
	@Subscribe(topics = "AddTexts", eventType = AddTextsEvent.class)
	public void onAddTexts(Event<AddTextsEvent> event)
	{
		final String layerName = event.getSource().getLayerName();
		final ArrayList<GlobeAnnotation> annotations = new ArrayList<GlobeAnnotation>();
		
		
		if(!this.cacheOfLayers.containsKey(layerName))
		{
			this.cacheOfLayers.addLayer(layerName, GlobeAnnotation.class);
			AnnotationLayer annotationLayer = new AnnotationLayer();
			annotationLayer.setName(layerName);
			earth.addLayer(annotationLayer);
			layers.updatePanel();
		}
		
		final AnnotationLayer layer = (AnnotationLayer) earth.getLayer(layerName);
		if(layer != null)
    	{
			for(Text t:event.getSource().getTexts())
			{
				this.cacheOfLayers.getLayer(layerName).update(t.getId(),t,t.getText());	
			}
			if(earth.getLayer("DataDisplayLayer").isEnabled() && this.selectedObjectData.getText() != null)
			{
				this.selectedObjectData.updateSelectedObject(this.cacheOfLayers.getLayer(layerName).getOriginalObjects(), Text.class);
			}
			final ArrayList<Annotation> cacheTmp = new ArrayList<Annotation>();
			for(String key: this.cacheOfLayers.getLayer(layerName).getConvertedObjects().keySet())
			{
				cacheTmp.add((GlobeAnnotation) this.cacheOfLayers.getLayer(layerName).getConvertedObjects().get(key));
			}
			
			java.awt.EventQueue.invokeLater(new Runnable()
	        {
	            public void run()
	            {
            		layer.setAnnotations(cacheTmp);
	            	earthView.update();
	            }
	        });
    	}
		else
    	{
    		System.out.println("Fail Layer "+layerName+" don't exist");
    	}
	}
	
	@Subscribe(topics = "DeleteLayer", eventType = DeleteLayerEvent.class)
	public void onDeleteLayer(Event<DeleteLayerEvent> event)
	{
		this.cacheOfLayers.removeLayer(event.getSource().getLayerName());
		earth.removeLayer(event.getSource().getLayerName());
		earthView.update();
		layers.updatePanel();
	}
	
	public void performCommandViewAction(ActionEvent e)
	{
		System.out.println(e.toString());
	}

	public void selected(SelectEvent arg0) {

		if(arg0.isLeftClick())
		{
			if(earth.getLayer("DataDisplayLayer").isEnabled())
			{
				System.out.println(arg0.getTopObject());
				if(arg0.getTopObject() != null)
				{
					EarthLayer layer = this.cacheOfLayers.findSelectedObject(arg0.getTopObject());
					if(layer != null)
					{
						Object selected = layer.findSelectedObject(arg0.getTopObject());
						if(selected != null)
						{
							if(selected instanceof MarkerPoint)
							{
								MarkerPoint m = (MarkerPoint) selected;
								this.selectedObjectData.setMarker(m);
//								dataLayer.setDataToDisplay(m.getData());
								if(m.getData().getImage()!= null)
								{
									imageView.diplayImage(m.getData().getImage());
									imageView.setVisible(true);
								}
							}
							else if(selected instanceof Icon)
							{
								Icon i = (Icon) selected;
								this.selectedObjectData.setIcon(i);
//								dataLayer.setDataToDisplay(i.getData());
								if(i.getData().getImage()!= null)
								{
									imageView.diplayImage(i.getData().getImage());
									imageView.setVisible(true);
								}
							}
							else if(selected instanceof Line)
							{
								Line l = (Line) selected;
								this.selectedObjectData.setLine(l);
//								dataLayer.setDataToDisplay(l.getData());
								if(l.getData().getImage()!= null)
								{
									imageView.diplayImage(l.getData().getImage());
									imageView.setVisible(true);
								}
							}
							else if(selected instanceof Text)
							{
								Text t = (Text) selected;
								this.selectedObjectData.setText(t);
//								dataLayer.setDataToDisplay(t.getData());
								if(t.getData().getImage()!= null)
								{
									imageView.diplayImage(t.getData().getImage());
									imageView.setVisible(true);
								}
							}
						}
						else
						{
							System.out.println("Fail to find object");
						}
					}
				}
			}
		}
	}


}
